package com.henry.chatkit.utils

import android.media.AudioAttributes
import android.media.MediaPlayer
import android.media.MediaRecorder
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.Log
import com.henry.chatkit.Constants
import com.henry.chatkit.messages.MessageProperties

/**
 * 录音最大60秒
 */
class AudioPlayer {

    companion object {
        val instance: AudioPlayer by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            AudioPlayer()
        }
    }

    private val MAGIC_NUMBER = 500
    private val MIN_RECORD_DURATION = 1000
    private var mRecordCallback: Callback? = null
    private var mPlayCallback: Callback? = null

    private var mAudioRecordPath: String? = null
    private var mPlayer: MediaPlayer? = null
    private var mRecorder: MediaRecorder? = null
    private var mHandler: Handler = Handler(Looper.getMainLooper())

    var playerId: String = ""

    fun startRecord(callback: Callback?) {
        mRecordCallback = callback
        if (mRecorder == null) {
            mRecorder = MediaRecorder()
        }
        try {
            mAudioRecordPath = Constants.VOICE_DIR + FileUtils.getVoiceName(null, "m4a")
            mRecorder!!.setAudioSource(MediaRecorder.AudioSource.MIC)
            // 使用mp4容器并且后缀改为.m4a，来兼容小程序的播放
            mRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            mRecorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)

            FileUtils.createOrExistsDir(Constants.VOICE_DIR)
            mRecorder!!.setOutputFile(mAudioRecordPath)
            Log.d("AudioPlayer", "mAudioRecordPath:$mAudioRecordPath")
            mRecorder!!.prepare()
            mRecorder!!.start()
            // 最大录制时间之后需要停止录制
            mHandler.removeCallbacksAndMessages(null)
            mHandler.postDelayed({
                stopInternalRecord()
                onRecordCompleted(true)
                toast("已达到最大语音长度")
            }, (MessageProperties.getInstance().audioMaxDuration * 1000).toLong())
        } catch (e: Exception) {
            Log.w("startRecord failed", e)
            stopInternalRecord()
            onRecordCompleted(false)
        }
    }

    fun stopRecord() {
        stopInternalRecord()
        onRecordCompleted(true)
    }

    private fun stopInternalRecord() {
        mHandler.removeCallbacksAndMessages(null)
        if (mRecorder == null) {
            return
        }
        mRecorder!!.release()
        mRecorder = null
    }

    fun startPlay(filePath: String?, id: String = "", callback: Callback?) {
        playerId = id
        startPlay(filePath, callback)
    }

    fun startPlay(filePath: String?, callback: Callback?) {
        mAudioRecordPath = filePath
        mPlayCallback = callback
        try {
            mPlayer = MediaPlayer()

            mPlayer!!.setDataSource(filePath)
            mPlayer!!.setOnCompletionListener {
                stopInternalPlay()
                onPlayCompleted(true)
            }
            mPlayer!!.prepare()
            mPlayer!!.start()
        } catch (e: Exception) {
            Log.w("startPlay failed", e)
            toast("语音文件已损坏或不存在")
            stopInternalPlay()
            onPlayCompleted(false)
        }
    }

    fun stopPlay() {
        stopInternalPlay()
        onPlayCompleted(false)
    }

    private fun stopInternalPlay() {
        if (mPlayer == null) {
            return
        }
        mPlayer!!.release()
        mPlayer = null
    }

    fun isPlaying(): Boolean {
        return mPlayer != null && mPlayer!!.isPlaying
    }

    private fun onPlayCompleted(success: Boolean) {
        mPlayCallback?.onCompletion(success)
        mPlayer = null
        mPlayCallback = null
    }

    private fun onRecordCompleted(success: Boolean) {
        mRecordCallback?.onCompletion(success)
        mRecorder = null
        mRecordCallback = null
    }

    fun getPath(): String? {
        return mAudioRecordPath
    }

    fun getDuration(): Int {
        if (TextUtils.isEmpty(mAudioRecordPath)) {
            return 0
        }
        var duration = 0
        // 通过初始化播放器的方式来获取真实的音频长度
        try {
            val mp = MediaPlayer()

            mp.setAudioAttributes(AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build())

            mp.setDataSource(mAudioRecordPath)
            mp.prepare()
            duration = mp.duration
            // 语音长度如果是59s多，因为外部会/1000取整，会一直显示59'，所以这里对长度进行处理，达到四舍五入的效果
            duration = if (duration < MIN_RECORD_DURATION) {
                0
            } else {
                duration + MAGIC_NUMBER
            }
        } catch (e: Exception) {
            Log.w("getDuration failed", e)
        }
        if (duration < 0) {
            duration = 0
        }
        return duration
    }

    interface Callback {
        fun onCompletion(success: Boolean)
    }

}